#! /bin/bash

## by huanlf@gmail.com 2008-03-07
## last modify 2008-04-08


# --------------- definition ----------------- #
## verbose flag
VERBOSE=

# --------------- white list ----------------- #

## ips that can be ignored
IGNORED_IPS=127.0.0.1

## we will try to figure out the local interface's ip later in function get_lanip
LANIPS=

## ports that can be ignored ( <= 1024 ), ok in lan/wan
IGNORED_PORTS=80,443

## programs that can be ignored, ok in lan/wan
IGNORED_PROGS=

# --------------- black list ----------------- #

## ports that not should be bond on wan ip
DANGER_PORTS=1-1024,3306

## programs that should not serve in wan
DANGER_PROGS=ssh*,mysqld

# --------------- functions ----------------- #

## try to get all lan ips
get_lanip()
{
    local ip=$(
        /sbin/ifconfig | 
        awk '/inet addr/ { 
            if ( $2 ~ /:172\./ || $2 ~ /:192\./ || $2 ~ /:10\./ ) {
                print substr( $2, 6 )
            }
        }'
    )

    [[ -z "$ip" ]] && return 1 || echo $ip
}

## just print listen_ip listen_port program_name
format()
{
    awk '
    { 
        sub(":", " ", $4)
        sub(/[0-9]*\//, "", $NF)
        gsub(/[()]/, "", $NF)
        sub(/^-$/, "unknow", $NF)
        print $4, $NF
    }' 
}

check_port()
{
    local port="$1"
    shift
    local list="$@"

    for p in $list; do
        case $p in
            *-*)
                local min=${p%%-*}
                local max=${p##*-}

                if (( min <= port )) && (( port <= max )); then
                    return 0
                fi
                ;;
            *)
                if (( p == port )); then
                    return 0
                fi
        esac
    done

    return 1
}

check_prog()
{
    local prog=$1
    shift
    local list="$@"

    for p in $list; do
        case $prog in
            $p)
                return 0
                ;;
        esac
    done

    return 1
}

## check ip,port,prog
check()
{
    local ok_ip ok_prog d_prog
    local ip port prog

    while read ip port prog; do

        [[ "$VERBOSE" ]] && echo -e "checking [$ip $port $prog]"

        # --- white list start --- #

        ## skip lan_ips and ips in ignored_list
        for ok_ip in $LANIPS ${IGNORED_IPS//,/ }; do
            [[ "$ok_ip" == "$ip" ]] && continue 2
        done

        ## skip ignored ports
        if check_port "$port" ${IGNORED_PORTS//,/ }; then
            continue
        fi

        ## skip ignored programs
        if check_prog "$prog" ${IGNORED_PROGS//,/ }; then
            continue
        fi

        # --- black list start --- #

        ## check dangerous ports
        if check_port "$port" ${DANGER_PORTS//,/ }; then
            echo -e "dangerous port in wan: [$ip:$port $prog]"
            continue
        fi

        ## check dangerous programs
        if check_prog "$prog" ${DANGER_PROGS//,/ }; then
            echo -e "dangerous serv in wan: [$ip:$port $prog]"
            continue
        fi

        ## other's are ignored
        [[ "$VERBOSE" ]] && echo -e "ignored list [$ip:$port $prog]"

    done
}

# --------------- main ----------------- #

if [[ $1 == '-v' ]] || [[ $1 == '--verbose' ]]; then
    VERBOSE=1
fi

LANIPS=$( get_lanip )
LAN_1=$( echo $LANIPS | awk '{ print $1 }' )

## exits if can not can one lan ip
: ${LANIPS:? CAN NOT GET LAN IP}

## to avoid asterisk expansion
tmpdir=$( mktemp -d 2>/dev/null || mkdir "/tmp/$(date +%s).$$.$RANDOM" )
command cd $tmpdir

netstat -lpnt --inet 2>/dev/null |
tail -n +3 |
format |
check  |
{
    echo -e "host: [$LAN_1]"
    cat
}

command cd
rmdir $tmpdir
